﻿// Asio session base class.
// Author: Jin Qing (http://blog.csdn.net/jq0123)

#ifndef SVR_COMMON_ASIO_ASIO_SESSION_BASE_H
#define SVR_COMMON_ASIO_ASIO_SESSION_BASE_H

#include <functional>
#include <unordered_map>  // for unordered_map

#include <boost/asio/ip/tcp.hpp>  // for socket
#include <boost/asio/spawn.hpp>  // for yield_context
#include <boost/asio/strand.hpp>

#include "rpc/rpc_callback.h"  // for RcpCallback
#include "rpc/rpc_data_vector.h"  // for RpcDataVector
#include "rpc/rpc_req_resp_fwd.h"  // for RpcResponse

class CMailBox;
class CAsioServer;

class CAsioSessionBase
{
public:
	explicit CAsioSessionBase(CAsioServer& rServer);
	virtual ~CAsioSessionBase();

public:
	uint64_t GetId() const;  // SessionId == MailBoxId

public:
	using socket = boost::asio::ip::tcp::socket;

protected:
	using yield_context = boost::asio::yield_context;
	bool SendRpcs(socket& rSocket, CMailBox& rMb, yield_context yield);
	bool ReadOne(socket& rSocket, yield_context yield);

protected:
	void WaitMs(unsigned int uMilliSeconds, yield_context yield);
private:
	using ReadBuf = std::vector<char>;
	void HandleData(const ReadBuf& rBuf);
	void HandleResponse(const rpc::RpcResponse& response);

	
private:
	virtual CMailBox& GetMailBox() = 0;
	virtual const CMailBox& GetMailBox() const = 0;

private:
	using LenVector = std::vector<uint32_t>;
	using DataVector = std::vector<std::string>;
	using BufVector = std::vector<boost::asio::const_buffer>;
	struct SendLenDataBuf
	{
		LenVector vLenNet;  // 包长（网络序）列表
		DataVector vData;  // 数据包
		BufVector vBuf;  // asio发送的缓冲区列表
	};

	// 填空发送缓冲区列表, 记录Rpc回调
	void PrepareRpcs(const RpcDataVector& vRpc, // 待发送Rpc列表
		SendLenDataBuf& rSendBuf);

protected:
	CAsioServer& m_rServer;
	boost::asio::io_service::strand m_strand;
	bool m_bConnected = false;

private:
	using RpcCbMap = std::unordered_map<uint32_t, RpcCallback>;
	RpcCbMap m_mapRpcCb;
	uint32_t m_uRpcId = 0;
};

#endif  // SVR_COMMON_ASIO_ASIO_SESSION_BASE_H
